'''
Created on Aug 23, 2010

@author: alia
'''
import logging
log = logging.getLogger('game')
log.debug("imported")

import pyknic 
import cocos
from cocos.director import director
from pyglet.event import EventDispatcher
from cocos.actions import *
import pyglet

from npc_sprite import NPCSprite, CreateNPCSprite
from player import UserControlledSprite
from mouse import  MouseManager
from lookup import BuildLookupTable,SortByName, SortByTile
from tile_layer import TileHandeler, TileLayer
from bg_layer import BGLayer
from level import Level
import anims
from hud import Hud
from force import Force
from level_complete import LevelComplete

import game_audio

class Game(cocos.layer.Layer, EventDispatcher): # must be layer - scene causes anims/actions to fail
    is_event_handler = True # for actions to work
    # Two set of collision
    # PvE - player looks after this one
    # PvNPC - we have to do here
    def __init__(self, level_description):
        super(Game, self).__init__()
        # Instead of: ???
        #cocos.layer.Layer.__init__(self)
        #EventDispatcher.__init__(self)

        # Setup layers
        # HUD
        self.hud = Hud(self)
                
        game_audio.next_song()

        #res = anims.GetFramesFromFile("images/nethackcreaturetiles32x32.png", [32,32])
        #player = UserControlledSprite(self, res[33], [200,200], None)
        player = UserControlledSprite(self, [200,200], None)
        self.level = Level(player, level_description)

        #TODO: MESSY!!
        mouse = MouseManager(player, self.level.scroller)
        self.level.set_mouse(mouse)
        
        self.add(self.level, z=-2)
        self.add(self.hud, z=-1)
        
        # Set up collision
        
        # collision detector
        self.cd = pyknic.collision.CollisionDetector()
      
        # define some groups
        self.cd.register_group('player', [player])
        #self.cd.register_group('mobs', [ref() for ref in self.level.ALL_MOBS])
        self.cd.register_group('mobs', self.level.ALL_MOBS)
        
        # define which group should collide with other
        self.cd.register_pair('player','mobs')
           
        # define specialized callback
        def collision_FN(a, b):
            if a.disabled or b.disabled:
                return
            # get list of things to do
            resp = b.collision_response(a)
            # do them!
            if resp is not None and len(resp)>0:
                log.debug( "Actions: ["+a.name+"<-->"+b.name+"] -> ["+str(resp)+"]")
                a.collision_action(resp)
                if resp.get("addXP",None) is not None:
                    self.dispatch_event("on_xp_gain")

        self.cd.register_narrow_func((UserControlledSprite,NPCSprite), collision_FN)

        #c = pyknic.rdc_rect(g)
        self.player = player
        self.schedule(self.update)

        self.apply_forces()

        self.do(Delay(3) +CallFunc(self.dispatch_event,'on_game_start') )
        
        self.push_handlers(self.on_save_point, self.on_player_die, self.on_complete_level)
        
        game_audio.play_song('music_background1.ogg')
        
    def on_complete_level(self):
        log.info("Level complete")
        self.parent.add(LevelComplete(True, self.hud.timer.element.text), z=10)
        self.unschedule(self.update)

    def on_player_freeze(self, *args ):
        log.info("freeze_player: "+str(args[0]))
        self.player.disable(args[0])

        
    def on_save_point(self):
        log.info("Save point @ "+str(self.player.position))
        self.level.set_player_start(self.player.position) 
          
    def on_player_die(self):
        # TODO: remove extra player dead message
        log.info("Player dead")
        def set_plr():
            log.info("Resetting player position")
            self.player.reset(self.level.player_start)
            self.do(FadeIn(2))
             
        self.do(FadeOut(2)+Delay(2) +CallFunc(set_plr))
        
    def add_object(self, object):
        self.add(object)

    def apply_forces(self):
        for npc in self.level.ALL_MOBS:            
            if(npc.force is not None):
                self.player.add_force(npc.force)


    def update(self, dt):
        self.level.update(dt)
        if self.player is not None:
            self.level.set_focus(self.player.x, self.player.y)

        # check collisions
        pairs = self.cd.check_broad() 
        #print pairs

        self.cd.check_narrow(pairs)
        
        # check collision with level
        self.level.collide(self.player)
        
        
        
Game.register_event_type('on_player_caught')   
Game.register_event_type('on_game_start')   
Game.register_event_type('on_xp_gain')   
Game.register_event_type('on_game_over')   
Game.register_event_type('on_game_win')          
Game.register_event_type('on_complete_level')   
Game.register_event_type('on_save_point')          
Game.register_event_type('on_player_die')
Game.register_event_type('on_player_freeze') 
 
def run(level):
     
    
    return Game(level)

if __name__ == '__main__':



    director.init(width=640, height=480, do_not_scale=True)    
    director.run(run())